﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Threading;

namespace Cepheus
{
    public class Settings<T> where T : class, ISettingsData, new()
    {
        static Settings<T> defaultInstance = null;

        public static Settings<T> Default
        {
            get
            {
                if (defaultInstance == null)
                    throw new Exception("Initialization is missing!");

                return defaultInstance;
            }
        }

        Type dataType;
        string file = null;
        SerializationType serializationType = SerializationType.XML;

        public T Data { get; set; }


        public static void Initialize(string file, SerializationType serializationType)
        {
            if (defaultInstance == null)
                defaultInstance = new Settings<T>(file, serializationType);
            else
                throw new Exception("Initialization already done!");

        }

        private Settings(string file, SerializationType serializationType)
        {
            this.file = file;
            this.serializationType = serializationType;
            this.dataType = typeof(T);

            ReloadData();

            //write all new values with their defaults to file
            SaveData();
        }

        public void ReloadData()
        {
            ExecuteAndRetryOnError(() =>
            {
                switch (serializationType)
                {
                    case SerializationType.Binary:
                        Data = (T)SerializationHelper.DeserializeBinary(file);
                        break;
                    case SerializationType.XML:
                        Data = (T)SerializationHelper.DeserializeXML(dataType, file);
                        break;
                }
            }, 4, 100);

            if (Data == null)
                Data = new T();

            Data.LoadComplete();
        }

        public void SaveData()
        {
            ExecuteAndRetryOnError(() =>
            {
                switch (serializationType)
                {
                    case SerializationType.Binary:
                        SerializationHelper.SerializeBinary(Data, file);
                        break;
                    case SerializationType.XML:
                        SerializationHelper.SerializeXML(Data, dataType, file);
                        break;
                }
            }, 4, 100);
        }

        private void ExecuteAndRetryOnError(Action action, int retryCount, int msWaitForRetry = 0)
        {
            int count = 0;
            while (count++ <= retryCount)
            {
                try
                {
                    if (count > 1 && msWaitForRetry > 0)
                        Thread.Sleep(msWaitForRetry);

                    action();
                    break;
                }
                catch (Exception ex)
                {
                    if (count > retryCount)
                        throw ex;
                }
            }
        }
    }
}
